#ifndef _CTREE_H_
#define _CTREE_H_

/*
 * Command tree structure.
 *
 * It's simple, leaf node was used as a command container, and non-leaf
 * node was used as entry to the deeper level commands.
 *
 * All nodes (include leaf and non-leaf) in the same level were orgnized
 * as a double linked cycle list. Every node has a pointer point to its
 * father, which is a non-leaf node. Also a non-leaf node has a pointer
 * point to its left-most child.
 *
 * Of cause, the root of command tree is a non-leaf node, but it has no
 * father, so its father pointer was set as NULL.
 */

#define CTREE_TYPE_NLEAF (1<<0)
#define CTREE_TYPE_LEAF  (1<<1)

#define DEFAULT_NAME     "shell"

struct ctree_node {
  char type;    /* CTREE_TYPE_NLEAF or CTREE_TYPE_LEAF */

  /* common member */
  char *name;

  struct ctree_node *father;
  struct ctree_node *child;
  struct ctree_node *lsibling;
  struct ctree_node *rsibling;

  /* CLI_TYPE_NLEAF only member */
  void (*prompt)(void);    /* if not NULL, use this function to output shell
			      prompt of this level */

  /* CLI_TYPE_LEAF only member */
  int (*action)(int argc, char **argv);
};

typedef struct ctree_node *ctree_node_t;
typedef ctree_node_t ctree_leaf_t;
typedef ctree_node_t ctree_nleaf_t;

/* exported variables */

extern ctree_nleaf_t current;

/* exported functions */

/*
 * ctree_new_entry - init a new entry to a command level
 *
 * @name        name string of this entry
 * @prompt      prompt message callback of this entry
 *
 * return %NULL on error, new command level entry on success.
 */
ctree_nleaf_t ctree_new_entry(char *name, void (*prompt)(void));

/*
 * ctree_new_cmd - init a new leaf for command container
 *
 * @name        name string of this command
 * @action      actions processed when exec this command
 *
 * return %NULL on error, new command container on success.
 */
ctree_leaf_t ctree_new_cmd(char *name, int (*action)(int, char**));

/*
 * ctree_regisger_node - add node to command tree.
 *
 * @father   command tree node to set as father
 * @node     node to be added to command tree
 */
void ctree_register_node(ctree_node_t father, ctree_node_t node);

/*
 * ctree_get_node - get command tree node by name in desired tree level
 *
 * @name  name of the node we are looking for
 *
 * return %NULL on failed, corresponding command tree node on success.
 */
ctree_node_t ctree_get_node(ctree_nleaf_t entry, char *name);

/*
 * ctree_init - initialize command tree
 *
 * @name     name string of command tree root.
 * @prompt   prompt message callback of top level commands.
 *
 * return -1 on error, 0 on success.
 */
int ctree_init(char *name, void (*prompt)(void));

/*
 * cli_fini - deinitialize cli engine
 */
void ctree_fini(void);

#endif
